////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Roman Ranzmaier (http://www.ranzmaier.at/contact.aspx).  All rights reserved.
// 
// Codeplex project: http://gadgeteernetworking.codeplex.com
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

using System;
using Microsoft.SPOT;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using Ranzmaier.NETMF.IO;

namespace Ranzmaier.NETMF.GadgeteerNetworking
{
    /// <summary>
    /// Fast and Easy TCPServer
    /// </summary>
    public class TcpClient : NetClientBase
    {
        
        private NetworkStream _stream;
        private bool disposed = false;
        private BinaryReader _reader = null;
        private BinaryWriter _writer = null;


        /// <summary>
        /// Gets a <see cref="BinaryReader"/> for the stream
        /// </summary>
        public BinaryReader Reader
        {
            get
            {
                if (_reader == null)
                    _reader = new BinaryReader(GetStream());
                return _reader;

            }
        }
      
        /// <summary>
        /// Gets a <see cref="BinaryWriter"/> for the stream
        /// </summary>
        public BinaryWriter Writer
        {
            get
            {
                if (_writer == null)
                    _writer = new BinaryWriter(GetStream());
                return _writer;

            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TcpClient"/> class.
        /// </summary>
        public TcpClient() : base()
        {
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TcpClient"/> class and connect to the specified <see cref="IPEndPoint"/>
        /// </summary>
        /// <param name="ep">The endpoint.</param>
        public TcpClient(IPEndPoint ep) :base(ep)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TcpClient"/> class and connects to the specified host and port
        /// </summary>
        /// <param name="hostname">The hostname or IP address.</param>
        /// <param name="port">The port to connect.</param>
        public TcpClient(string hostname, int port) : base(hostname,port)
        {
        }

        /// <summary>
        /// Connects to the specified hostname:port
        /// </summary>
        /// <param name="hostname">The hostname.</param>
        /// <param name="port">The port.</param>
        public override void Connect(string hostname, int port)
        {
            Connect(hostname, port, ProtocolType.Tcp);
        }


        /// <summary>
        /// Connects the specified endpoint
        /// </summary>
        /// <param name="ep">The endpoint.</param>
        public override void Connect(IPEndPoint ep)
        {            
            if (ep == null)
                throw new ArgumentNullException("ep");
            _socket.Connect(ep);
            Active = true;
        }


        /// <summary>
        /// Gets the network stream.
        /// </summary>
        /// <returns></returns>
        public NetworkStream GetStream()
        {
            if (_stream == null)
            {
                _stream = new NetworkStream(_socket, true);
            }
            return _stream;
        }



        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        public override void Dispose()
        {
            if (disposed)
                return;
            if (_reader != null)
                _reader.Close();
            if (_writer != null)
                _writer.Close();

            System.IO.Stream dataStream = _stream;
            if (dataStream != null)
                dataStream.Close();
            dataStream = null;

            base.Dispose();
            disposed = true;
        }
    }
}
